package com.xayy.health.mgt.task;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.kawins.mybatis.util.SnowflakeId;
import com.xayy.health.core.enums.ModuleEnum;
import com.xayy.health.core.enums.RunningStatusEnum;
import com.xayy.health.core.enums.TaskStatusEnum;
import com.xayy.health.core.manager.DynamicSchedulerManager;
import com.xayy.health.core.utils.LocalCache;
import com.xayy.health.mgt.model.HealthAlgorithmManage;
import com.xayy.health.mgt.model.TaskChildInfo;
import com.xayy.health.mgt.model.TaskInfo;
import com.xayy.health.mgt.model.vo.CalculateVo;
import com.xayy.health.mgt.service.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.List;

/**
 * 定时执行数据处理-任务列表
 *
 * @author zhangxa
 */
@Slf4j
@Component
@EnableScheduling
public class ScheduledTask {

    @Autowired
    private DynamicSchedulerManager dynamicSchedulerManager;
    @Autowired
    private TaskInfoService taskInfoService;
    @Autowired
    private TaskChildInfoService taskChildInfoService;
    @Autowired
    private DataQualityService dataQualityService;
    @Autowired
    private DiagnoseService diagnoseService;
    @Autowired
    private CalculateService calculateService;
    @Autowired
    private HealthAlgorithmManageService healthAlgorithmManageService;

    @Autowired
    private  DiagnoseSingleParamService diagnoseSingleParamService;

    @Autowired
    private HealthAutoRunService healthAutoRunService;

    @Autowired
    private FaultReportService faultReportService;

    /**
     * 批量预处理上线运行
     */
    @SneakyThrows
//    @Scheduled(fixedDelay = 30000)
    public void onlineBatchPreData() {
        log.info("批量预处理定时器开始执行。。。。。。。。。。。。。。。。。。");
        List<TaskInfo> taskInfos = taskInfoService.select(TaskInfo.builder().type(1).status(1).isBatch(0).build());
        if (CollUtil.isNotEmpty(taskInfos)) {
            taskInfos.forEach((x) -> {
                Date startTime = x.getEndTime();
                Date endTime = DateUtil.offsetMinute(startTime, (int) (Double.parseDouble(x.getCycle()) * 60));
                DateTime now = DateUtil.date();
                int compare = DateUtil.compare(now, endTime);
                if (compare >= 0) {
                    String name = x.getName() + "-" + DateUtil.format(startTime, "yyyyMMddHHmmss") + "-"
                            + DateUtil.format(endTime, "yyyyMMddHHmmss");
                    TaskChildInfo taskChildInfo = TaskChildInfo.builder().taskId(x.getId()).name(name)
                            .fileLogo(x.getFileLogo()).legendName(x.getLegendName()).satelliteCode(x.getSatelliteCode()).status(TaskStatusEnum.RUNNING.getCode()).params(x.getParams())
                            .tyTag(x.getTyTag()).tcTag(x.getTcTag()).phTag(x.getPhTag()).startTime(startTime).endTime(endTime)
                            .modelName(x.getModelName()).predNumber(x.getPredNumber()).createdTime(new Date()).timeSpan(x.getTimeSpan()).build();
                    try {
                        log.info("时间{}", taskChildInfo);
                        taskChildInfoService.insertSelective(taskChildInfo);
                        // 设置结束时间防止项目重启重复运行
                        x.setEndTime(endTime);
                        taskInfoService.updateByIdSelective(x);

                        dataQualityService.asyncExcuteTask(taskChildInfo);
                    } catch (Exception e) {
                        taskChildInfo.setDataSituation("无");
                        taskChildInfoService.updateByIdSelective(taskChildInfo);
                        try {
                            faultReportService.faultReport(ModuleEnum.SHZD.getCode(), ModuleEnum.SHZD.getMsg(),"处理任务数据出错",null);
                        } catch (UnknownHostException ex) {
                            throw new RuntimeException(ex);
                        }
                        log.error("处理任务：{}，任务类型：{} 时间段：{}到{}数据出错", x.getName(), x.getType(), DateUtil.format(startTime, "yyyy-MM-dd HH:mm:ss"), DateUtil.format(endTime, "yyyy-MM-dd HH:mm:ss"),e);
                    }
                }
            });
        }
    }


    /**
     * 数据预处理上线运行
     */
    @SneakyThrows
//    @Scheduled(fixedDelay = 30000)
    public void onlinePreData() {
        log.info("数据处理定时器开始执行。。。。。。。。。。。。。。。。。。");
        TaskInfo taskInfo = TaskInfo.builder().type(1).status(1).isBatch(null).build();
        List<TaskInfo> taskInfoList = taskInfoService.selectPreData(taskInfo);
        if (CollUtil.isNotEmpty(taskInfoList)) {
            taskInfoList.forEach((x) -> {
                Date startTime = x.getEndTime();
                Date endTime = DateUtil.offsetMinute(startTime, (int) (Double.parseDouble(x.getCycle()) * 60));
                DateTime now = DateUtil.date();
                int compare = DateUtil.compare(now, endTime);
                if (compare >= 0) {
                    String name = x.getName() + "-" + DateUtil.format(startTime, "yyyyMMddHHmmss") + "-"
                            + DateUtil.format(endTime, "yyyyMMddHHmmss");
                    TaskChildInfo taskChildInfo = TaskChildInfo.builder().taskId(x.getId()).name(name)
                            .fileLogo(x.getFileLogo()).legendName(x.getLegendName()).satelliteCode(x.getSatelliteCode()).status(TaskStatusEnum.RUNNING.getCode()).params(x.getParams())
                            .tyTag(x.getTyTag()).tcTag(x.getTcTag()).phTag(x.getPhTag()).startTime(startTime).endTime(endTime)
                            .modelName(x.getModelName()).predNumber(x.getPredNumber()).createdTime(new Date()).timeSpan(x.getTimeSpan()).build();
                    try {
                        log.info("时间{}", taskChildInfo);
                        taskChildInfoService.insertSelective(taskChildInfo);
                        // 设置结束时间防止项目重启重复运行
                        x.setEndTime(endTime);
                        taskInfoService.updateByIdSelective(x);

                        dataQualityService.asyncExcuteTask(taskChildInfo);
                    } catch (Exception e) {
                        taskChildInfo.setDataSituation("无");
                        taskChildInfoService.updateByIdSelective(taskChildInfo);
                        try {
                            faultReportService.faultReport(ModuleEnum.SHZD.getCode(), ModuleEnum.SHZD.getMsg(),"处理任务数据出错",null);
                        } catch (UnknownHostException ex) {
                            throw new RuntimeException(ex);
                        }
                        log.error("处理任务：{}，任务类型：{} 时间段：{}到{}数据出错", x.getName(), x.getType(), DateUtil.format(startTime, "yyyy-MM-dd HH:mm:ss"), DateUtil.format(endTime, "yyyy-MM-dd HH:mm:ss"),e);
                    }
                }
            });
        }
    }

    /**
     * 事后诊断上线运行
     */
    @SneakyThrows
//    @Scheduled(fixedDelay = 30000)
    public void onlineFault() {
        log.info("事后诊断定时器开始执行。。。。。。。。。。。。。。。。。。");
        List<TaskInfo> taskInfos = taskInfoService.select(TaskInfo.builder().type(2).status(1).build());
        if (CollUtil.isNotEmpty(taskInfos)) {
            taskInfos.parallelStream().forEach((x) -> {
                //多参
                if (x.getCheckMultiparameter() == 1) {
                    //长期运行
                    if (x.getRunningStatus().equals(RunningStatusEnum.LONG_RUNNING.getCode())) {
                        Date multiLongStartTime = x.getLongRunningTime();
                        Date multiLongEndTime = DateUtil.offsetMinute(multiLongStartTime, (int) (Double.parseDouble(x.getCycle()) * 60));
                        /*构建子任务并且保存*/
                        TaskChildInfo taskChildInfo = buildChildTask(x);
                        //设置结束时间防止项目重启重复运行
                        x.setLongRunningTime(multiLongEndTime);
                        DateTime now = DateUtil.date();
                        //事后诊断长期运行,运行的时间大于了当前系统的时间，任务就停掉
                        int compare = DateUtil.compare(multiLongEndTime, now);
                        if (compare > 0) {
                            x.setStatus(0);
                            taskInfoService.updateByIdSelective(x);
                        } else {
                            taskInfoService.updateByIdSelective(x);
                            TaskChildInfo taskChildInfo1 = taskChildInfoService.selectOne(taskChildInfo);
                            try {
                                diagnoseService.asyncExcuteTask(taskChildInfo1, x, null);
                            } catch (UnknownHostException e) {
                                throw new RuntimeException(e);
                            }
                        }

                    } else if (x.getRunningStatus().equals(RunningStatusEnum.RUN_IN_STAGES.getCode())) {
                        Date multiStageStartTime = x.getEndTime();
                        Date multiStageEndTime = DateUtil.offsetMinute(multiStageStartTime, (int) (Double.parseDouble(x.getCycle()) * 60));
                        int compare = DateUtil.compare(x.getRunInStagesTime(), multiStageEndTime);
                        if (compare >= 0) {
                            /*构建子任务并且保存*/
                            TaskChildInfo taskChildInfo = buildChildTask(x);
                            //设置结束时间防止项目重启重复运行
                            x.setEndTime(multiStageEndTime);
                            taskInfoService.updateByIdSelective(x);
                            TaskChildInfo taskChildInfo1 = taskChildInfoService.selectOne(taskChildInfo);
                            try {
                                diagnoseService.asyncExcuteTask(taskChildInfo1, x, null);
                            } catch (UnknownHostException e) {
                                throw new RuntimeException(e);
                            }
                        } else {
                            x.setStatus(0);
                            taskInfoService.updateByIdSelective(x);
                        }
                    }
                } else {
                    /*单参数任务*/
                    /*该方法最后又掉用了diagnoseService.asyncExcuteTask() 方法，所以这里判断了单参数和多参数，diagnoseService.asyncExcuteTask() 里又判断了一次*/
                    try {
                        diagnoseSingleParamService.singleParamRunTask(x);
                    } catch (UnknownHostException e) {
                        throw new RuntimeException(e);
                    }
                }
            });
        }
    }

    /**
     * 事后诊断/趋势预测上线运行,检查停止的任务是否可以开始运行
     */
    @SneakyThrows
//    @Scheduled(fixedDelay = 10000)
    public void checkTaskIsRun() {
        /*查询事后诊断数据*/
        List<TaskInfo> taskInfos = taskInfoService.select(TaskInfo.builder().type(2).status(0).build());
        /*添加趋势预测数据*/
        taskInfos.addAll(taskInfoService.select(TaskInfo.builder().type(3).status(0).build()));
        taskInfos.forEach(task ->{
            if(task.getPauseEndTime() != null){
                /*判断时间是否在当前时间之后*/
                boolean after = new Date().after(task.getPauseEndTime());
                /*如果任务暂停时间大于当前时间并且未执行过则任务开始运行*/
                if(after && 1 != task.getPauseEndTimeIsExecute()){
                    task.setStatus(1);
                    task.setPauseEndTimeIsExecute(1);
                    taskInfoService.updateByIdSelective(task);
                }
            }
        });
    }


    private TaskChildInfo buildChildTask(TaskInfo x){
        Date multiLongStartTime = x.getLongRunningTime();
        Date multiLongEndTime = DateUtil.offsetMinute(multiLongStartTime, (int) (Double.parseDouble(x.getCycle()) * 60));
        String name = x.getName() + "-" + DateUtil.format(multiLongStartTime, "yyyyMMddHHmmss") + "-" + DateUtil.format(multiLongEndTime, "yyyyMMddHHmmss");
        /*构建子任务*/
        TaskChildInfo multiLongTaskChildInfo = TaskChildInfo.builder()
                .taskId(x.getId())
                .name(name)
                .satelliteCode(x.getSatelliteCode())
                .status(TaskStatusEnum.RUNNING.getCode())
                .params(x.getParams())
                .tyTag(x.getTyTag())
                .tcTag(x.getTcTag())
                .phTag(x.getPhTag())
                .startTime(multiLongStartTime)
                .endTime(multiLongEndTime)
                .modelName(x.getModelName())
                .predNumber(x.getPredNumber())
                .timeSpan(x.getTimeSpan())
                .checkMultiparameter(x.getCheckMultiparameter())
                .build();
        taskChildInfoService.insert(multiLongTaskChildInfo);
        return multiLongTaskChildInfo;
    }

    /**
     * 趋势预测上线运行
     */
    @SneakyThrows
//    @Scheduled(fixedDelay = 30000)
    public void onlineCalculate() {
        log.info("趋势预测定时器开始执行。。。。。。。。。。。。。。。。。。");
        List<TaskInfo> taskInfos = taskInfoService.select(TaskInfo.builder().type(3).status(1).build());
        if (CollUtil.isNotEmpty(taskInfos)) {
            taskInfos.forEach((x) -> {
                Date startTime;
                Date endTime;
                //预测是否需要执行
                boolean runFlag=true;
                //任务重启后开始时间大于结束时间时，将结束时间与开始时间置为相同，任务继续运行
                int compareStartAndEnd = DateUtil.compare(x.getStartTime(), x.getEndTime());
                if (compareStartAndEnd > 0) {
                    runFlag=false;
                    endTime = x.getStartTime();
                    startTime = endTime;
                } else {
                    if (StrUtil.isNotEmpty(x.getStep())) {
                        startTime = DateUtil.offsetMinute(x.getStartTime(), (Integer.parseInt(x.getStep())));
                    } else {
                        startTime = x.getEndTime();
                    }
                    endTime = DateUtil.offsetMinute(startTime, Integer.parseInt(x.getCycle()));
                }
                DateTime now = DateUtil.date();
                int compare = DateUtil.compare(now, endTime);
                if (compare >= 0) {
                    x.setStartTime(startTime);
                    x.setEndTime(endTime);
                    taskInfoService.updateByIdSelective(x);
                    if(runFlag){
                        try {
                            calculateService.asyncExcuteTask(x);
                        } catch (UnknownHostException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            });
        }
    }

//    @PostConstruct
//    public void init() {
//        log.info("加载趋势预测定时器开始执行。。。。。。。。。。。。。。。。。。");
//        List<TaskInfo> taskInfos = taskInfoService.select(TaskInfo.builder().type(3).status(1).build());
//        if (CollUtil.isNotEmpty(taskInfos)) {
//            taskInfos.forEach((x) -> {
//                dynamicSchedulerManager.addOrUpdateTask(
//                        String.valueOf(x.getId()),
//                        x.getCron(),
//                        () -> pretask(x)
//                );
//            });
//        }
//    }

    public void pretask(TaskInfo x){
        log.info("趋势预测定时器开始执行。。。。。。。。。。。。。。。。。。");
        Date startTime;
        Date endTime;
        //预测是否需要执行
        boolean runFlag=true;
        //任务重启后开始时间大于结束时间时，将结束时间与开始时间置为相同，任务继续运行
        int compareStartAndEnd = DateUtil.compare(x.getStartTime(), x.getEndTime());
        if (compareStartAndEnd > 0) {
            runFlag=false;
            endTime = x.getStartTime();
            startTime = endTime;
        } else {
            if (StrUtil.isNotEmpty(x.getStep())) {
                startTime = DateUtil.offsetMinute(x.getStartTime(), (Integer.parseInt(x.getStep())));
            } else {
                startTime = x.getEndTime();
            }
            endTime = DateUtil.offsetMinute(startTime, Integer.parseInt(x.getCycle()));
        }
        DateTime now = DateUtil.date();
        int compare = DateUtil.compare(now, endTime);
        if (compare >= 0) {
            x.setStartTime(startTime);
            x.setEndTime(endTime);
            taskInfoService.updateByIdSelective(x);
            if(runFlag){
                try {
                    calculateService.asyncExcuteTask(x);
                } catch (UnknownHostException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }


    public void algorithmStatus() {
        List<HealthAlgorithmManage> algorithmManageList = healthAlgorithmManageService.selectAlgorithmByType();
        algorithmManageList.forEach(x -> x.setServerState(StrUtil.isNotBlank(LocalCache.TIMED_CACHE.get(x.getAlgorithmCode()))));
        if (CollUtil.isNotEmpty(algorithmManageList)) {
            healthAlgorithmManageService.updateListById(algorithmManageList);
        }
    }


    /**
     * 健康态势自动运行任务
     * type=5时，为健康态势评估任务
     */
    public void healthAutoRunTask() {
        log.info("健康态势定时器开始执行。。。。。。。。。。。。。。。。。。");
        List<TaskInfo> taskInfos = taskInfoService.select(TaskInfo.builder().type(5).status(1).build());
        if (CollUtil.isNotEmpty(taskInfos)) {
            taskInfos.forEach((x) -> {
                Date startTime = x.getEndTime();
                Date endTime = DateUtil.offsetDay(startTime, Integer.parseInt(x.getCycle()));
                DateTime now = DateUtil.date();
                int compare = DateUtil.compare(now, endTime);
                if (compare >= 0) {
                    String name = x.getName() + "-" + DateUtil.format(startTime, "yyyyMMddHHmmss") + "-"
                            + DateUtil.format(endTime, "yyyyMMddHHmmss");
                    Long id=new SnowflakeId().genId("tb_task_child_info","id");
                    TaskChildInfo taskChildInfo = TaskChildInfo.builder().id(id).taskId(x.getId()).name(name)
                            .status(TaskStatusEnum.RUNNING.getCode())
                            .startTime(startTime).endTime(endTime)
                            .createdTime(new Date()).build();
                    try {
                        taskChildInfoService.insertSelective(taskChildInfo);
                        // 设置结束时间防止项目重启重复运行
                        x.setEndTime(endTime);
                        taskInfoService.updateByIdSelective(x);
                        CalculateVo calculateVo = healthAutoRunService.setHealthAutoRunTaskInfo(x, endTime, id);
                        healthAutoRunService.healthAutoRunTask(calculateVo);
                        taskChildInfo.setStatus(TaskStatusEnum.DONE.getCode());
                        taskChildInfoService.updateByIdSelective(taskChildInfo);
                    } catch (Exception e) {
                        taskChildInfoService.updateByIdSelective(taskChildInfo);
                        try {
                            faultReportService.faultReport(ModuleEnum.SHZD.getCode(), ModuleEnum.SHZD.getMsg(),"处理任务数据出错",null);
                        } catch (UnknownHostException ex) {
                            throw new RuntimeException(ex);
                        }
                        log.error("处理任务：{}，任务类型：{} 时间段：{}到{}数据出错", x.getName(), x.getType(), DateUtil.format(startTime, "yyyy-MM-dd HH:mm:ss"), DateUtil.format(endTime, "yyyy-MM-dd HH:mm:ss"), e);
                    }
                }
            });
        }
    }
}
